package com.bocloud.cmp.driver.providers.os;

import java.util.List;

import org.openstack4j.api.Builders;
import org.openstack4j.api.exceptions.ClientResponseException;
import org.openstack4j.model.common.ActionResponse;
import org.openstack4j.model.storage.block.Volume;
import org.openstack4j.model.storage.block.VolumeSnapshot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bocloud.cmp.driver.convertor.BeanConvert;
import com.bocloud.cmp.driver.convertor.os.ConvertVolumes;
import com.bocloud.cmp.driver.providers.VolumeDriver;
import com.bocloud.cmp.model.SnapshotModel;
import com.bocloud.cmp.model.VolumeModel;
import com.bocloud.common.model.BsmResult;
import com.google.common.collect.Lists;

/**
 * OpenStack 云硬盘驱动实现
 * 
 * @author dmw
 *
 */
public class OSVolumeDriver extends OSDriver implements VolumeDriver {

    private static Logger logger = LoggerFactory.getLogger(OSVolumeDriver.class);

    /**
     * 
     */
    public OSVolumeDriver() {
        super();
    }

    public OSVolumeDriver(String endpoint, String username, String password, String tenant, String domain,
            String project, Version version) {
        super(endpoint, username, password, tenant, domain, project, version);
    }

    @Override
    public BsmResult list() {
        List<VolumeModel> models = Lists.newArrayList();

        List<? extends Volume> volumes = Lists.newArrayList();
        if (!this.accessable()) {
            logger.error(this.getError());
            return new BsmResult(false, this.getError());
        }
        volumes = this.getClient().blockStorage().volumes().list();
        if (null != volumes && !volumes.isEmpty()) {
            for (Volume volume : volumes) {
                BeanConvert<VolumeModel, Volume> volumeConvert = new ConvertVolumes();
                models.add(volumeConvert.convertModel(volume));
            }
        }
        return new BsmResult(true, models, "success");
    }

    @Override
    public BsmResult create(VolumeModel volume) {
        boolean bootable = null == volume.getBootVolume() ? false : volume.getBootVolume();
        if (!this.accessable()) {
            logger.error(this.getError());
            return new BsmResult(false, this.getError());
        }
        try {
            Volume volumeResult = this.getClient().blockStorage().volumes()
                    .create(Builders.volume().name(volume.getName()).description(volume.getRemark())
                            .size(volume.getSize()).bootable(bootable).build());
            volume.setVolumeId(volumeResult.getId());
            volume.setGmtCreate(volumeResult.getCreated());
            volume.setStatus(volumeResult.getStatus().name());
            volume.setZone(volumeResult.getZone());
            return new BsmResult(true, volume, "创建成功!");
        } catch (ClientResponseException e) {
            logger.error("云硬盘创建失败:{}", e);
            if (413 == e.getStatus()) {
                return new BsmResult(false, "磁盘空间不足!");
            }
            return new BsmResult(false, "创建失败！");
        }
    }

    @Override
    public BsmResult remove(String volumeId) {
        if (!this.accessable()) {
            logger.error(this.getError());
            return new BsmResult(false, this.getError());
        }
        ActionResponse response = this.getClient().blockStorage().volumes().delete(volumeId);
        if (response.isSuccess()) {
            return new BsmResult(true, "云硬盘删除成功！");
        } else {
            logger.error("remove instance [{}] failed :{}", volumeId, response.getFault());
            return new BsmResult(false, "云硬盘删除失败！");
        }
    }

    @Override
    public BsmResult detail(String volumeId) {
        if (!this.accessable()) {
            logger.error(this.getError());
            return new BsmResult(false, this.getError());
        }
        Volume volume = this.getClient().blockStorage().volumes().get(volumeId);
        if (null == volume) {
            return new BsmResult(false, "云硬盘不存在！");
        }

        BeanConvert<VolumeModel, Volume> volumeConvert = new ConvertVolumes();
        return new BsmResult(true, volumeConvert.convertModel(volume), "success");
    }

    @Override
    public BsmResult modify(VolumeModel volume) {
        if (!this.accessable()) {
            logger.error(this.getError());
            return new BsmResult(false, this.getError());
        }
        ActionResponse response = this.getClient().blockStorage().volumes().update(volume.getVolumeId(),
                volume.getName(), volume.getRemark());
        if (null != response) {
            return new BsmResult(true, "操作成功！");
        } else {
            logger.error("");
            return new BsmResult(false, "操作失败！");
        }
    }

    @Override
    public BsmResult snapshot(SnapshotModel model) {
        try {
            if (!this.accessable()) {
                logger.error(this.getError());
                return new BsmResult(false, this.getError());
            }
            VolumeSnapshot volumnBuilder = Builders.volumeSnapshot().description(model.getRemark())
                    .name(model.getName()).volume(model.getVolumeId()).build();

            VolumeSnapshot snapshot = this.getClient().blockStorage().snapshots().create(volumnBuilder);

            if (null == snapshot) {
                return new BsmResult(false, "failed!");
            } else {
                return new BsmResult(true, convert(snapshot), "success");
            }
        } catch (ClientResponseException e) {
            logger.error("创建快照失败！", e);
            if (400 == e.getStatus()) {
                return new BsmResult(false, "云硬盘正在使用中,创建快照失败！");
            }
            return new BsmResult(false, "创建快照失败！");
        }
    }

    private SnapshotModel convert(VolumeSnapshot snapshot) {
        if (null == snapshot) {
            return null;
        }
        SnapshotModel model = new SnapshotModel();
        model.setGmtCreate(snapshot.getCreated());
        model.setName(snapshot.getName());
        model.setSize(snapshot.getSize());
        model.setSnapshotId(snapshot.getId());
        model.setVolumeId(snapshot.getVolumeId());
        model.setStatus(snapshot.getStatus().name());
        return model;
    }

}